#include "stdafx.h"
#include "MaterialCreateShaderDialog.h"
#include "MaterialTemplateGenerator.h"
#include <LitCore.h>

namespace Lit
{
	namespace Editor
	{
		namespace Material
		{
			ShaderDef::ShaderDef(){}
			ShaderDef::ShaderDef( const std::string &nam, const std::string &lang, const std::string &prof, const std::string &entry_point )
				: name(nam), language(lang), profile(prof), entryPoint(entry_point)
			{}
			ShaderDef::ShaderDef( const ShaderDef& def )
				: name(def.name), language(def.language), profile(def.profile), entryPoint(def.entryPoint)
			{}
			ShaderDef::~ShaderDef(){}

			HeaderDef::HeaderDef( ){}
			HeaderDef::HeaderDef( const HeaderDef& def )
			{
				author = def.author;
				date = def.date;
				version = def.version;
				typeDesc = def.typeDesc;
				typeName = def.typeName;
			}
			HeaderDef& HeaderDef::operator=( const HeaderDef& def )
			{
				author = def.author;
				date = def.date;
				version = def.version;
				typeDesc = def.typeDesc;
				typeName = def.typeName;
				return *this;
			}

			std::string HeaderDef::generate() const
			{
				return String	("// Header Generation Test !\n")
								("// arg: %%\n").arg(int(10)).str();
			}
			ProgramDef::ProgramDef( bool accept_, const std::string &shaderNam, const std::string &nam, bool has_definition, bool has_vertex, const ShaderDef& vertex, bool has_pixel, const ShaderDef& pixel )
				: vertexShader(vertex)
				, pixelShader(pixel)
				, hasVertex(has_vertex)
				, hasPixel(has_pixel)
				, name( nam )
				, shaderName( shaderNam )
				, hasDefinition( has_definition )
				, accepted(accept_)
			{
				headers.typeName = FilePath(nam).extension();
				if( headers.typeName == "material" ) headers.typeDesc = "Ogre Material File";
				else if( headers.typeName == "compositor" ) headers.typeDesc = "Ogre Compositor File";
				else if( headers.typeName == "particle" ) headers.typeDesc = "Ogre Particle File";
				else if( headers.typeName == "program" ) headers.typeDesc = "Ogre Program File";
				else if(	headers.typeName == "cg" || 
							headers.typeName == "asm" || 
							headers.typeName == "glsl" || 
							headers.typeName == "hlsl" ) 
					headers.typeDesc = "Ogre Shader File";
			}
			ProgramDef::ProgramDef( const ProgramDef& def )
				: vertexShader(def.vertexShader)
				, pixelShader(def.pixelShader)
				, hasVertex(def.hasVertex)
				, hasPixel(def.hasPixel)
				, name(def.name)
				, shaderName( def.shaderName )
				, hasDefinition( def.hasDefinition )
				, accepted(def.accepted)
			{}
			ProgramDef::~ProgramDef(){}

			std::string ProgramDef::generate() const
			{
				TemplateGenerator gen = TemplateGenerator( name, headers.author );
				return gen.generateProgram(*this);
			}
				
			std::string ProgramDef::generateVertex() const
			{
				TemplateGenerator gen = TemplateGenerator( name, headers.author );
				return gen.generateVertexShader(vertexShader.language, vertexShader.entryPoint);
			}
			std::string ProgramDef::generatePixel() const
			{
				TemplateGenerator gen = TemplateGenerator( name, headers.author );
				return gen.generatePixelShader(pixelShader.language, pixelShader.entryPoint);
			}


			CreateShaderDialog::CreateShaderDialog( QWidget * parent, const std::string &default_shader_name, unsigned int options, const std::string &vertex_prefix, const std::string &vertex_suffix, const std::string &pixel_prefix, const std::string &pixel_suffix ) 
				: QDialog( parent )
				, mOptions(options)
				, mVertexNamer(vertex_prefix, vertex_suffix, "_")
				, mPixelNamer(pixel_prefix, pixel_suffix, "_")
				, mProgramNamer("", "program",".")
			{ 
				ui.setupUi( this ); 
				ui.vertProfile->clear();
				ui.fragProfile->clear();
				ui.vertProfile->addItems( QStringList() << "vs_1_1" << "vs_2_0" << "vs_2_x" << "vs_3_0" << "arbvp1" << "vp20" << "vp30" << "vp40" );
				ui.fragProfile->addItems( QStringList() << "ps_1_1"<<"ps_1_2"<<"ps_1_3"<<"ps_1_4"<<"ps_2_0"<<"ps_2_x"<<"ps_3_0"<<"ps_3_x"<<"arbfp1"<<"fp20"<<"fp30"<<"fp40"<<"gpu_gp"<<"gp4_gp"<<"glsles" );
				
				ui.hasVert->setVisible( ( options & VertexShader ) != NULL );
				ui.hasFrag->setVisible( ( options & PixelShader ) != NULL );
				ui.genProgram->setVisible( ( options & ProgramDefinition ) != NULL );
				

				ui.author->setText( TO_QT(Lit::Root::HostName) );
				ui.creationDate->setDateTime( QDateTime::currentDateTime() );
				connect( ui.shaderName, SIGNAL(textChanged(const QString&)), this, SLOT(shaderNameChanged(const QString&)) );

				ui.shaderName->setFocus();
				ui.shaderName->setText( TO_QT(default_shader_name) );
				ui.shaderName->selectAll();
			}
			CreateShaderDialog::~CreateShaderDialog()
			{}

			bool CreateShaderDialog::hasFrag() const{ return ui.hasFrag->isChecked(); }
			bool CreateShaderDialog::hasVert() const{ return ui.hasVert->isChecked(); }
				
			std::string CreateShaderDialog::vertProfile() const{ return FROM_QT(ui.vertProfile->currentText()); }
			std::string CreateShaderDialog::fragProfile() const{ return FROM_QT(ui.fragProfile->currentText()); }
				
			std::string CreateShaderDialog::vertEntryPoint() const{ return FROM_QT(ui.vertEntryPoint->text()); }
			std::string CreateShaderDialog::fragEntryPoint() const{ return FROM_QT(ui.fragEntryPoint->text()); }
				
			std::string CreateShaderDialog::vertLanguage() const{ return FROM_QT(ui.vertLang->currentText()); }
			std::string CreateShaderDialog::fragLanguage() const{ return FROM_QT(ui.fragLang->currentText()); }
			std::string CreateShaderDialog::progName() const{ 
				std::string ret = FROM_QT(ui.programName->text()); 
				size_t p=0;
				if( (p=ret.find_last_of('.')) != std::string::npos ) return ret.substr( 0, p );
				return ret;
			}
			std::string CreateShaderDialog::vertName() const{ 
				std::string ret = FROM_QT(ui.vertexName->text()); 
				size_t p=0;
				if( (p=ret.find_last_of('.')) != std::string::npos ) return ret.substr( 0, p );
				return ret;
			}
			std::string CreateShaderDialog::fragName() const{ 
				std::string ret = FROM_QT(ui.fragName->text()); 
				size_t p=0;
				if( (p=ret.find_last_of('.')) != std::string::npos ) return ret.substr( 0, p );
				return ret;
			}


			bool CreateShaderDialog::hasProgram() const{ return ui.genProgram->isChecked(); }

			void CreateShaderDialog::shaderNameChanged(const QString& to)
			{
				std::string base(FROM_QT(to));
				NameModifier mod(NameModifier::FilePath);
				
				base = mod.generate( base );
				ui.programName->setText( TO_QT(mProgramNamer(base)) );
				ui.vertexName->setText( TO_QT(mVertexNamer(base)+"."+vertLanguage()) );
				ui.fragName->setText( TO_QT(mPixelNamer(base)+"."+fragLanguage()) );
			}

			
			ProgramDef CreateShaderDialog::exec()
			{
				int cod = QDialog::exec();
				ProgramDef ret;
				ret.headers.author = FROM_QT(ui.author->text());
				ret.headers.date = FROM_QT(ui.creationDate->text());
				ret.hasDefinition = hasProgram();
				ret.hasVertex = hasVert();
				ret.hasPixel = hasFrag();
						
				ret.name = progName();
				ret.shaderName = FROM_QT(ui.shaderName->text());
				ret.pixelShader = ShaderDef( fragName(), fragLanguage(), fragProfile(), fragEntryPoint() );
				ret.vertexShader = ShaderDef( vertName(), vertLanguage(), vertProfile(), vertEntryPoint() );
				ret.accepted = ((cod == QDialog::Accepted)?true:false);
				return ret;
			}
			ProgramDef CreateShaderDialog::createShader( QWidget * parent, const std::string &shaderName, unsigned int options, const std::string &vertex_prefix, const std::string &vertex_suffix, const std::string &pixel_prefix, const std::string &pixel_suffix )
			{
				CreateShaderDialog* dlg( new CreateShaderDialog(parent, shaderName, options, vertex_prefix, vertex_suffix, pixel_prefix, pixel_suffix) );
				ProgramDef ret(dlg->exec());
				delete dlg, dlg = NULL;
				return ret;
			}

			unsigned int CreateShaderDialog::getOptions() const{ return mOptions; }
			void CreateShaderDialog::setOptions( unsigned int opt ){ mOptions = opt; }
			void CreateShaderDialog::addOption( DialogOption opt ){ mOptions |= opt; }
			bool CreateShaderDialog::hasOption( DialogOption opt ) const{ return ((mOptions&opt)!=NULL); }
			bool CreateShaderDialog::hasOptions( unsigned int opt ) const{ return ((mOptions&opt)!=NULL); }
		};
	};
};